package com.ymm.websocket.demo.server;


import com.ymm.websocket.demo.model.RoleInfo;
import com.ymm.websocket.demo.utils.enums.RoleEnum;
import com.ymm.websocket.demo.utils.enums.StateEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description: WebSocketServer
 * 定义WebSocket server（多例的，多线程的）
 * roleType表示角色类型,0表示客服，1表示用户
 * @Author: Xuecheng Li
 * @CreateTime: 2022-08-10 10:53
 * @Version: 1.0.0
 */
@Slf4j
@ServerEndpoint("/api/websocketServiceHashMap/{role}")
@Component
public class WebSocketServerCustomerHashMap {

    /**
     * 静态变量，用来记录当前在线人数（司机和客服的信息）
     */
    private static AtomicInteger onlineCustomerCount = new AtomicInteger(0);
    private static AtomicInteger onlineServiceCount = new AtomicInteger(0);

    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。(不用重写WebSocketServer，直接判断是否同一个对象就行)
     */
    private static HashMap<Session, WebSocketServerCustomerHashMap> waitingCustomerMap = new HashMap<>();
    private static List<Session> waitingCustomerList = new ArrayList<>();

    private static HashMap<Session, WebSocketServerCustomerHashMap> availableServiceMap = new HashMap<>();
    private static List<Session> availableServiceList = new ArrayList<>();


    /**
     * 记录通话中客服
     */
    private static HashMap<Session, WebSocketServerCustomerHashMap> busyServiceMap = new HashMap<>();
    private static List<Session> busyServiceList = new ArrayList<>();

    /**
     * 记录通话中客户
     */
    private static HashMap<Session, WebSocketServerCustomerHashMap> busyCustomerMap = new HashMap<>();
    private static List<Session> busyCustomerList = new ArrayList<>();


    /**
     * 保存角色核心信息
     */
    private RoleInfo roleInfo = new RoleInfo();

    @OnOpen
    public void onOpen (Session session, @PathParam("role") Integer role) {

        //1.记录登录身份信息
        roleInfo.setSession(session);
        roleInfo.setRole(role);
        roleInfo.setState(0);

        //2.判断角色
        if (role.equals(RoleEnum.CUSTOMER_SERVICE.getCode())) {
            //2.1 寻找等待中的用户
            if (onlineCustomerCount.get() < 1) {
                //2.1.1 进入客服等待池
                onlineServiceCount.getAndIncrement();

                availableServiceMap.put(session, this);
                availableServiceList.add(session);

                log.info("没有等待的客户，客服进入等待池");

                // 给客服发送消息，"无等待客户，进入等待状态"
                try {
                    sendMessageSelf("无等待客户，进入等待状态");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                //2.1.2 绑定用户(寻找等待用户，直接用第一个即可)
                Session waitingCustomerSession = waitingCustomerList.get(0);
                WebSocketServerCustomerHashMap user = waitingCustomerMap.get(waitingCustomerSession);

                //客服与客户绑定session
                user.roleInfo.setBandingRoleSession(roleInfo.getSession());
                roleInfo.setBandingRoleSession(user.roleInfo.getSession());

                //更新客服状态和客户状态
                roleInfo.setState(1);
                user.roleInfo.setState(1);

                //清除客服等待池和客户等待池，并添加客服与客户繁忙池
                waitingCustomerMap.remove(waitingCustomerSession);
                waitingCustomerList.remove(waitingCustomerSession);
                onlineCustomerCount.getAndDecrement();

                availableServiceMap.remove(session);
                availableServiceList.remove(session);
                onlineServiceCount.getAndDecrement();

                busyServiceMap.put(session, this);
                busyServiceList.add(session);

                busyCustomerMap.put(waitingCustomerSession, user);
                busyCustomerList.add(waitingCustomerSession);

                //绑定成功，发送提示消息
                try {
                    sendMessageSelf("与用户建立连接，准备接客");
                    sendMessage("与客服建立连接，很高兴为您服务");
                    log.info("与用户{}建立连接，准备进入服务",user.roleInfo.getSession().getId());
                } catch (IOException e) {
                    log.error("websocket连接中断，请重试!");
                    e.printStackTrace();
                }
            }
        } else {
            //2.2 是否存在空闲客服
            if (onlineServiceCount.get() < 1) {

                //进入用户等待池
                waitingCustomerMap.put(session, this);
                waitingCustomerList.add(session);
                onlineCustomerCount.getAndIncrement();

                log.info("没有空闲客服，进入等待");

                //给客户发送消息：“无空闲客服，请等待”
                try {
                    sendMessageSelf("无空闲客服，请等待");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                //与客服绑定
                Session customerServiceSession = availableServiceList.get(0);
                WebSocketServerCustomerHashMap customerService = availableServiceMap.get(customerServiceSession);

                // 客户与客服相互绑定
                roleInfo.setBandingRoleSession(customerService.roleInfo.getSession());
                customerService.roleInfo.setBandingRoleSession(roleInfo.getSession());

                //更新客户和客服状态
                roleInfo.setState(1);
                customerService.roleInfo.setState(1);

                // 清除空闲客服池
                availableServiceMap.remove(customerServiceSession);
                availableServiceList.remove(customerServiceSession);
                onlineServiceCount.getAndDecrement();

                // 添加繁忙客服池
                busyServiceMap.put(customerServiceSession, customerService);
                busyServiceList.add(customerServiceSession);

                //添加繁忙客户池
                busyCustomerMap.put(session, this);
                busyCustomerList.add(session);

                //绑定成功，发送提示消息
                try {
                    sendMessageSelf("与客服建立连接，很高兴为您服务");
                    sendMessage("与客户建立连接，准备接客");
                    log.info("与客服{}建立连接，准备进入服务",customerService.roleInfo.getSession().getId());
                } catch (IOException e) {
                    log.error("websocket连接中断，请重试!");
                    e.printStackTrace();
                }
            }
        }

    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        //判断是用户还是客服
        if (roleInfo.getRole().equals(RoleEnum.CUSTOMER_SERVICE.getCode())) {
            // 处理客服未结束服务关闭会话的异常 TODO

            // 繁忙状态关闭
            if (roleInfo.getState().equals(StateEnum.BUSY.getCode())) {
                //客户解除与客服连接，并发送提示消息
                Session bindingUserSession = roleInfo.getBandingRoleSession();
                WebSocketServerCustomerHashMap bindingUserWebSocket = busyCustomerMap.get(bindingUserSession);

                bindingUserWebSocket.roleInfo.setState(StateEnum.AVAILABLE.getCode());
                bindingUserWebSocket.roleInfo.setBandingRoleSession(null);

                //进入用户等待池，并用户解除繁忙池
                waitingCustomerMap.put(bindingUserSession, bindingUserWebSocket);
                waitingCustomerList.add(bindingUserSession);
                onlineCustomerCount.getAndIncrement();

                busyCustomerMap.remove(bindingUserSession);
                busyCustomerList.remove(bindingUserSession);

                log.info("连接中的客服意外离开");

                //给客户发送消息：“无空闲客服，请等待”
                try {
                    sendMessageTarget("客服意外离开，请等待", bindingUserSession);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                //解除繁忙客服池
                busyServiceList.remove(roleInfo.getSession());
                busyServiceMap.remove(roleInfo.getSession());

            } else { // 空闲状态关闭

                onlineServiceCount.getAndDecrement();
                availableServiceList.remove(roleInfo.getSession());
                availableServiceMap.remove(roleInfo.getSession());
            }



//            try {
//                sendMessage("客服已离开，结束本次会话");
//            } catch (IOException e) {
//                log.error("无绑定用户，客服直接下线");
//                e.printStackTrace();
//            }
        } else {

            //解除客户与客服的绑定，释放客服
            if (roleInfo.getState().equals(StateEnum.BUSY.getCode())) {
                //解除连接，释放客服，并给客服提示消息
                Session customerServiceSession = roleInfo.getBandingRoleSession();
                WebSocketServerCustomerHashMap serverCustomerWebSocket = busyServiceMap.get(customerServiceSession);

                serverCustomerWebSocket.roleInfo.setBandingRoleSession(null);

                busyServiceMap.remove(customerServiceSession);
                busyServiceList.remove(customerServiceSession);
                serverCustomerWebSocket.roleInfo.setState(StateEnum.AVAILABLE.getCode());

                // 更新available客服池及在线客服数量
                availableServiceMap.put(customerServiceSession, serverCustomerWebSocket);
                availableServiceList.add(customerServiceSession);
                onlineServiceCount.getAndIncrement();

                try {
                    sendMessageTarget("客户已离开，即将分配新的客户", customerServiceSession);
                } catch (IOException e) {
                    log.warn("客户已离开");
                    e.printStackTrace();
                }

                //清除繁忙客户池
                busyCustomerMap.remove(roleInfo.getSession());
                busyCustomerList.remove(roleInfo.getSession());
            } else {

                // 直接释放客户等待池即可
                waitingCustomerList.remove(roleInfo.getSession());
                waitingCustomerMap.remove(roleInfo.getSession());

                onlineCustomerCount.getAndDecrement();
            }



//            //给客服和客户分别发送消息
//            try {
//                sendMessageTarget("会话结束，感谢您的咨询", roleInfo.getSession());
//                sendMessageTarget("客户已离开", customerService.roleInfo.getSession());
//            } catch (IOException e) {
//                log.warn("系统用户离开错误");
//                e.printStackTrace();
//            }

        }

        //2.

//        //断开连接情况下，更新主板占用情况为释放
//        log.info("释放的sid为：{}",sid);
//        //这里写你 释放的时候，要处理的业务
//        log.info("有一连接关闭！当前在线人数为：{}",onlineCount.get());

    }

    /**
     * 收到客户端消息后调用的方法
     * @Param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {

        System.out.println(roleInfo.getRole() + "发送了消息" + message);

        if (roleInfo.getState().equals(StateEnum.AVAILABLE.getCode())) {

            if (roleInfo.getRole().equals(RoleEnum.CUSTOMER_SERVICE.getCode())) {
                //给客服发送消息
                try {
                    sendMessageSelf("无客户连接，无法发送消息");
                } catch (IOException e) {
                    log.error("发消息失败！！！，请重试");
                    e.printStackTrace();
                }
            } else {
                //给客户发送消息
                try {
                    sendMessageSelf("目前无客服连接，请连接成功后重试");
                } catch (IOException e) {
                    log.error("发消息失败！！！，请重试");
                    e.printStackTrace();
                }
            }

        } else {
            try {
                sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


    /**
     * @Param session
     * @Param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
//        if (roleInfo.getRole().equals(RoleEnum.CUSTOMER_SERVICE.getCode())) {
//            if (roleInfo.getBandingRoleSession() != null) {
//                try {
//                    sendMessage("客服意外故障，已离开，系统正在为您连接新的客服");
//
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }

        error.printStackTrace();
        log.error("发生错误");
    }


    /**
     * 主动给用户的绑定对象推送消息
     */
    private void sendMessage(String message) throws IOException {
        System.out.println("准备发送消息：" + message);

        Session targetSession = roleInfo.getBandingRoleSession();
        if (targetSession == null) {
            System.out.println("当前没有客户会话，消息发送无效");
            return;
        }
        targetSession.getBasicRemote().sendText(message);
    }

    /**
     * 主动给指定用户推送消息
     */
    private void sendMessageTarget(String message, Session session) throws IOException {
        System.out.println("准备发送消息：" + message);

        if (session == null) {
            System.out.println("没有会话，直接结束");
            return;
        }
        session.getBasicRemote().sendText(message);
    }


    /**
     * 主动给目标用户自身推送消息
     */
    private void sendMessageSelf(String message) throws IOException {
        System.out.println("准备发送消息：" + message);

        Session session = roleInfo.getSession();
        if (session == null) {
            System.out.println("没有会话，直接结束");
            return;
        }
        session.getBasicRemote().sendText(message);
    }

    /**
     * 寻找空闲客服
     * @Param: []
     * @return: void
     */
    private void searchOnlineService() {

    }

    /**
     * 寻找等待客户
     * @Param: []
     * @return: void
     */
    private void searchOnlineCustomer() {

    }
}
